         nls
         sbt      "Useful Equates"
         ttl      "SPEED/ASM Version 2.0"
;
;
;
; ANIX Equates.
;
INPUT    equ      $0200
;
ANIXWARM equ      $A000
PUTC     equ      $A006
PRINT    equ      $A01B
READLN   equ      $A01E
TSTDIG   equ      $A05A
TSTALPHA equ      $A057
PRTINT1  equ      $A027
;
VALUE    epz      $FA
;
;
;
; Constants
;
BELL     con      $87
CR       con      $8D
;
;
;
;
;
;
; SPEED/ASM Zero Page Equates
;
;
STRPTR   epz      0
RTNADRS  epz      STRPTR+2
ADRS     epz      RTNADRS+2
;
ASAVE    epz      ADRS+2
XSAVE    epz      ASAVE+1
YSAVE    epz      XSAVE+1
FORMAT   epz      YSAVE+1
GXSAVE   epz      FORMAT+1
INPUTNDX epz      GXSAVE+1
;
;
; String vars- Don't touch!
;
FREEMEM  epz      $50
VARPTR   epz      FREEMEM+2
STRLEN   epz      VARPTR+2
VARSTPTR epz      STRLEN+1
COLCTPTR epz      VARSTPTR+2
;
;
;
;
; Various Macros
;
         .md      INC16
         lcl      INC16LBL
         inc      ?0
         bne      INC16LBL
         inc      ?0+1
INC16LBL
         rls      INC16LBL
         .me
;
;
;
;
         sbt      "PRINTF Subroutine"
         pag
;
PRINTF   sta      ASAVE
         stx      XSAVE
         sty      YSAVE
STRINGPT epz      COLCTPTR+2
;
         pla
         sta      STRPTR
         sta      RTNADRS
         pla
         sta      STRPTR+1
         sta      RTNADRS+1
;
; Search for the end of the format string.
;
         ldy      #1
SRCHEND  lda      (RTNADRS),Y
         beq      >0
         iny
         bne      SRCHEND
         jmp      PRTFERR
;
; Adjust RTNADRS so that it points at the first address record
; beyond the format string.
;
^0       tya
         sec
         adc      RTNADRS
         sta      RTNADRS
         bcc      NEXTPRF
         inc      RTNADRS+1
;
;
; Okay, start printing the specified data.
;
NEXTPRF  jsr      INCSP
PRTDATA  ldy      #0
         lda      (STRPTR),Y
         beq      PRTFDONE
         cmp      #"%"                  ;PRINTF ESC character.
         beq      DOPRFESC
;
DOIMM    lda      (STRPTR),Y
         jsr      PUTC
         jmp      NEXTPRF
;
; If the end of the string was encountered, finish up and quit.
;
PRTFDONE lda      ASAVE
         ldx      XSAVE
         ldy      YSAVE
         jmp      (RTNADRS)             ;Return to caller.
;
PRTFERR  brk
;
;
;
DOPRFESC jsr      INCSP
         ldy      #0
         sty      FORMAT
         lda      (STRPTR),Y
         jsr      TSTDIG
         bcs      >1                    ;If no digit
         jsr      GET_FMT
^1       lda      (STRPTR),Y
         jsr      TSTALPHA              ;Converts l.c. -> U.C.
         cmp      #"D"
         beq      DODEC
         cmp      #"C"
         beq      DOCHAR
         cmp      #"S"
         bne      DOIMM
;
; Output a string here.
;
         jsr      GETADRS               ;Get address of string.
         ldy      #0
         lda      (ADRS),Y              ;Get address of string.
         tax
         iny
         lda      (ADRS),Y
         sta      ADRS+1
         stx      ADRS
;
OUTSTR   lda      (ADRS),Y
         beq      OUTSPCS
         jsr      PUTC
         iny
         bne      OUTSTR
;
OUTSPCS  cpy      FORMAT
         bge      >4
         lda      #" "
         jsr      PUTC
         iny
         bne      OUTSPCS
;
^4       jmp      NEXTPRF
;
;
DOCHAR   jsr      GETADRS
         lda      (ADRS),Y
         jsr      PUTC
         iny
         bne      OUTSPCS               ;Always taken.
;
;
;
;
DODEC    jsr      GETADRS
         lda      (ADRS),Y
         sta      VALUE
         iny
         lda      (ADRS),Y
         sta      VALUE+1
;
         lda      FORMAT                ;See if 0 was specified
         beq      DO_ALL
;
         ldx      #4
SIZELP   lda      VALUE
         cmp      T10L,X
         lda      VALUE+1
         sbc      T10H,X
         bge      FOUNDIT
         dex
         bne      SIZELP
;
FOUNDIT  inx                            ;X=# of print positions.
         stx      GXSAVE
         lda      FORMAT
         sub      GXSAVE
         bmi      DO_ALL
         tax
         lda      #" "
PSPCS2   jsr      PUTC
         dex
         bne      PSPCS2
;
DO_ALL   jsr      PRTINT1
         jmp      NEXTPRF
;
;
T10L     byt      1,10,100,1000,10000
T10H     hby      1,10,100,1000,10000
;
;
;
;
INCSP    inc      STRPTR
         bne      >0
         inc      STRPTR+1
^0       rts
;
;
;
GET_FMT  lda      (STRPTR),Y
         and      #$0F
         sta      FORMAT
         jsr      INCSP
         lda      (STRPTR),Y
         jsr      TSTDIG
         bcs      NOT_DIG
         asl      FORMAT
         lda      FORMAT
         asl
         asl
         adc      FORMAT                ;*10
         sta      FORMAT
         lda      (STRPTR),Y
         and      #$0F
         adc      FORMAT
         sta      FORMAT
         jsr      INCSP
NOT_DIG  rts
;
;
GETADRS  ldy      #1
         lda      (RTNADRS),Y
         sta      ADRS+1
         dey
         lda      (RTNADRS),Y
         sta      ADRS
         lda      RTNADRS
         add      #2
         sta      RTNADRS
         bcc      >9
         inc      RTNADRS+1
;
^9       rts
;
;
         sbt      "SCANF Subroutine"
         pag
;
;
; SCANF- Reads a string of characters from the keyboard
; using a format string to determine the input data type. 
;
SCANF    sta      ASAVE
         stx      XSAVE
         sty      YSAVE
;
         jsr      READLN                ;Read data from keyboard.
         ldx      #0
         stx      INPUTNDX
;
         pla
         sta      RTNADRS
         pla
         sta      RTNADRS+1
         inc      RTNADRS
         bne      >0
         inc      RTNADRS+1
;
^0       lda      RTNADRS
         sta      STRPTR
         lda      RTNADRS+1
         sta      STRPTR+1
;
; Now search for the end of the format string.
;
         ldy      #0
FNDENDFM lda      (RTNADRS),Y
         beq      FNDIT
         iny
         bne      FNDENDFM
         inc      RTNADRS+1
         jmp      FNDENDFM
;
FNDIT    tya
         sec                            ;Skip zero byte
         adc      RTNADRS
         sta      RTNADRS
         bcc      SKIPJUNK
         inc      RTNADRS+1
;
;
; Now STRPTR points at the format string and RTNADRS points at the first
; parameter.
;
SKIPJUNK ldy      #0
         _INC16   STRPTR
         lda      (STRPTR),Y
         bne      >4
         jmp      (RTNADRS)             ;Return to caller
;
^4       cmp      #"%"                  ;percent signs
         bne      SKIPJUNK
;
         _INC16   STRPTR
         lda      (STRPTR),Y
         and      #$DF                  ;l.c. -> U.C.
         cmp      #"D"                  ;Decimal
         beq      DECIN
         cmp      #"C"
         beq      CHARIN
         cmp      #"S"
         bne      SKIPJUNK
;
; Input a string at this point.
;
         ldx      INPUTNDX
         lda      INPUT,X               ;Test for EOLN
         cmp      #CR                   ;If at EOLN,
         bne      >0                    ;read a new line.
         jsr      READLN
         ldx      #0
         stx      INPUTNDX
;
^0       dex
FNDEOLN  inx
         lda      INPUT,X
         cmp      #$8D
         bne      FNDEOLN
;
; Compute the length of this string.
;
         txa
         sub      INPUTNDX
         tax
         lda      (RTNADRS),Y           ;Get var pointer.
         sta      ADRS
         iny
         lda      (RTNADRS),Y
         tay
         sta      ADRS+1
         lda      ADRS
         jsr      ALLOCATE
         ldy      #0                    ;Get the address of the
         lda      (ADRS),Y              ;allocated storage.
         tax
         iny
         lda      (ADRS),Y
         sta      ADRS+1
         stx      ADRS
         ldx      INPUTNDX              ;Now copy the input data.
         ldy      #$FF
COPYINPS iny
         inx
         lda      INPUT - 1,X
         sta      (ADRS),Y
         cmp      #CR
         bne      COPYINPS
;
         lda      #0
         sta      (ADRS),Y
         jmp      ADD2RTN
;
;
; CHARIN- Reads a single character
;         from the input buffer.
;
CHARIN   ldy      #0
         lda      (RTNADRS),Y
         sta      ADRS
         iny
         lda      (RTNADRS),Y
         sta      ADRS+1
         ldx      INPUTNDX
         lda      INPUT,X
         dey
         sta      (ADRS),Y
         inc      INPUTNDX
         jmp      SKIPJUNK
;
;
; DECIN- Decimal input routine.
;
;
DECIN
ADD2RTN  stx      INPUTNDX
         lda      RTNADRS
         add      #2
         sta      RTNADRS
         bcc      >3
         inc      RTNADRS+1
^3       jmp      SKIPJUNK
;
;
;
;
;
;
;
; If a percent sign is encountered, then we have format record item.
;
;
;
;
         sbt      "SPEED/ASM String Package"
         pag
;
**********************************
*
*     String Support Package
*
* Routines supported:
*
*
*
* ALLOCATE- Allocates storage for
*           a string.
*
* COLLECT-  Performs garbage col-
*           lection operation.
*
*
**********************************
;
;
;
;
; ALLOCATE- Allocates storage for
;           a string.
;
;  The address of the string var
; to be allocated is passed in
; (A,Y).  The length of the string
; to be stored is passed in X.
;
;
ALLOCATE sta      VARPTR
         sty      VARPTR+1
         stx      STRLEN
         txa
         add      FREEMEM
         tax
         lda      FREEMEM+1
         adc      #0
         cpx      #ENDSTR               ;Beyond the end?
         sbc      /ENDSTR
         blt      NOGRBG                ;If not, no garbage collection.
         jsr      COLLECT               ;If so, must perform garbage collect.
;
; Now see if we have enough memory.
;
         lda      STRLEN
         add      FREEMEM
         tax
         lda      FREEMEM+1
         adc      #0
         cpx      #ENDSTR
         sbc      /ENDSTR
         blt      NOGRBG
;
; Oh no!  We're really out of memory.
;
         jsr      PRINT
         byt      CR,CR,BELL,"String Memory Full Error!",0
         jmp      ANIXWARM
;
;
;
;
;
NOGRBG   ldy      #0
         lda      VARPTR                ;Set up back link.
         sta      (FREEMEM),Y
         iny
         lda      VARPTR+1
         sta      (FREEMEM),Y
;
         dey
         lda      FREEMEM
         add      #2
         sta      (VARPTR),Y
         sta      FREEMEM
         iny
         lda      FREEMEM+1
         adc      /2
         sta      (VARPTR),Y
         sta      FREEMEM+1
;
         lda      FREEMEM
         sec                            ;Adjust for zero
         adc      STRLEN                ;terminator byte.
         sta      FREEMEM
         bcc      >0
         inc      FREEMEM+1
;
^0       rts
;
;
;
;
; COLLECT- Performs garbage collection operation.
;
; On entry:
;
;  FREEMEM points to the end of the free memory space.
;  ENDSTR is the end of available memory.
;  STARTSTR is the beginning of available memory.
;
; On return:
;
;  FREEMEM points to the beginning of free memory.
;
;
COLLECT  lda      #STARTSTR
         sta      STRINGPT
         sta      COLCTPTR
         lda      /STARTSTR
         sta      STRINGPT+1
         sta      COLCTPTR+1
;
COLLCTLP lda      STRINGPT              ;See if we're done yet.
         cmp      FREEMEM
         lda      STRINGPT+1
         sbc      FREEMEM+1
         blt      MORE2GO
;
; All done, set FREEMEM=COLCTPTR.
;
         lda      COLCTPTR
         sta      FREEMEM
         lda      COLCTPTR+1
         sta      FREEMEM+1
         rts
;
;
MORE2GO  lda      STRINGPT
         add      #2
         sta      VARSTPTR
         lda      STRINGPT+1
         adc      /2
         sta      VARSTPTR+1
         ldy      #0
         lda      (VARSTPTR),Y
         cmp      STRINGPT
         bne      DOCOLLCT
         iny
         lda      (VARSTPTR),Y
         cmp      STRINGPT+1
         beq      DOCOLLCT
;
;
; This string is not in use, adjust only stringpt.
;
         lda      STRINGPT
         add      #2                    ;Skip over backlink.
         sta      STRINGPT
         bcc      >9
         inc      STRINGPT+1
;
^9       ldy      #$FF
SKIPSTRP iny
         beq      BADSTR
         lda      (STRINGPT),Y
         bne      SKIPSTRP
         tya
         sec
         adc      STRINGPT
         sta      STRINGPT
         bcc      CLCTLP
         inc      STRINGPT+1
         bcs      CLCTLP                ;Always taken
;
;
; Must move string.
;
DOCOLLCT ldy      #0
CLCTLP   lda      (STRINGPT),Y
         sta      (COLCTPTR),Y          ;Move backlink.
         iny
         lda      (STRINGPT),Y
         sta      (COLCTPTR),Y
         lda      STRINGPT              ;Adjust past link.
         add      #2
         sta      STRINGPT
         bcc      >1
         inc      STRINGPT+1
;
^1       lda      COLCTPTR
         add      #2
         sta      COLCTPTR
         bcc      >2
         inc      COLCTPTR+1
;
^2       dey
         dey
MOVLP    iny
         beq      BADSTR
         lda      (STRINGPT),Y
         sta      (COLCTPTR),Y
         bne      MOVLP
         tya
         add      STRINGPT
         sta      STRINGPT
         bcc      >2
         inc      STRINGPT+1
;
^2       tya
         add      COLCTPTR
         sta      COLCTPTR
         bcc      >3
         inc      COLCTPTR
^3       jmp      COLLCTLP
;
;
BADSTR   jsr      PRINT
         byt      CR,CR,BELL,"String Space Error!",CR,0
         jmp      ANIXWARM
;
;
;
STARTSTR dfs      $9000 - *
ENDSTR
;
         end
